/*
 * Copyright (C) 2016
 * <tanghaifeng-gz@loongson.cn> <pengren.mcu@qq.com>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 *
 */
#include <common.h>
#include <clk.h>
#include <asm/io.h>

#include <mach/ls1x.h>
#include <mach/regs-clk.h>

DECLARE_GLOBAL_DATA_PTR;

static void calc_clocks(void)
{
	unsigned long pll_freq;

#if defined(CONFIG_CPU_LOONGSON1A)
	{
		gd->cpu_clk = CPU_CLOCK_RATE;
		gd->mem_clk = APB_CLOCK_RATE;
		gd->bus_clk = gd->mem_clk / 2;
	}
#elif defined(CONFIG_CPU_LOONGSON1B)
	{
		unsigned int pll = readl(LS1X_CLK_PLL_FREQ);
		unsigned int ctrl = readl(LS1X_CLK_PLL_DIV);
		pll_freq = (12 + (pll & 0x3f)) * OSC_CLK / 2 + ((pll >> 8) & 0x3ff) * OSC_CLK / 1024 / 2;
		gd->cpu_clk = pll_freq / ((ctrl & DIV_CPU) >> DIV_CPU_SHIFT);
		gd->mem_clk = pll_freq / ((ctrl & DIV_DDR) >> DIV_DDR_SHIFT);
		gd->bus_clk = gd->mem_clk / 2;
		gd->arch.pll_clk = pll_freq;
	}
#elif defined(CONFIG_CPU_LOONGSON1C)
	{
		unsigned int pll_freq = readl(LS1X_CLK_PLL_FREQ);
		unsigned int clk_div = readl(LS1X_CLK_PLL_DIV);
		pll_freq = ((pll_freq >> 8) & 0xff) * OSC_CLK / 4;
		if (clk_div & DIV_CPU_SEL) {
			if(clk_div & DIV_CPU_EN) {
				gd->cpu_clk = pll_freq / ((clk_div & DIV_CPU) >> DIV_CPU_SHIFT);
			} else {
				gd->cpu_clk = pll_freq / 2;
			}
		} else {
			gd->cpu_clk = OSC_CLK;
		}
		gd->mem_clk = gd->cpu_clk / ((1 << ((pll_freq & 0x3) + 1)) % 5);
		gd->bus_clk = gd->mem_clk;
		gd->arch.pll_clk = pll_freq;
	}
#endif
}

int mach_cpu_init(void)
{
	calc_clocks();

	return 0;
}

int dram_init(void)
{
	gd->ram_size = get_ram_size ((long *)CONFIG_SYS_SDRAM_BASE, CONFIG_SYS_SDRAM_SIZE);

	return 0;
}

#ifdef CONFIG_DISPLAY_CPUINFO
const char *get_core_name(void)
{
	u32 proc_id;
	const char *str;

	proc_id = read_c0_prid();
	switch (proc_id) {
	case 0x00004220:
		str = "Loongson GS232";
		break;
	default:
		str = "Unknown";
	}

	return str;
}

int print_cpuinfo(void)
{
	printf("Core: %s\n", get_core_name());
	printf("Speed: Cpu @ %ld MHz/ Mem @ %ld MHz/ Bus @ %ld MHz\n",
			gd->cpu_clk/1000000, gd->mem_clk/1000000, gd->bus_clk/1000000);
	return 0;
}
#endif
